package cn.zhouchao.basic.service.impl;


import cn.zhouchao.basic.config.BussinessException;
import cn.zhouchao.basic.constant.LoginConstant;
import cn.zhouchao.basic.constant.RegisterConstant;
import cn.zhouchao.basic.dto.SmsCodeDto;
import cn.zhouchao.basic.service.VerifyCodeService;
import cn.zhouchao.basic.util.StrUtils;
import cn.zhouchao.basic.util.VerifyCodeUtils;
import cn.zhouchao.user.domain.User;
import cn.zhouchao.user.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VerifyCodeServiceImpl implements VerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    /**
     * 获取图形验证码
     *
     * @param redisKey
     * @return
     */
    @Override
    public String graph(String redisKey) throws IOException {
        // 1.生成一个验证码
        String randomString = StrUtils.getComplexRandomString(4);
        // 将验证码转成base64
        String base64Graph = VerifyCodeUtils.VerifyCode(100, 50, randomString);
        // 2.存到reids中 (当前时间戳 randomString),ttl:过期的剩余时间
        redisTemplate.opsForValue().set(redisKey, randomString, RegisterConstant.IMAGE_CODE_TTL, TimeUnit.MINUTES);
        // 3.返回图形验证码
        return base64Graph;
    }

    /**
     * 获取手机验证码
     *
     * @param dto
     */
    @Override
    public void smsCode(SmsCodeDto dto) {
        // 判断获取验证码的类型 注册页面 register.html 【P：172】
        if ("register".equals(dto.getType())) { // 类型：手机号注册
            // 注册获取手机验证码
            // ******************* 参数相关验证 ********************
            imageVerify(dto); // 不同：手机号注册发送验证码，他需要先经过这个图形验证码
            // ******************* 发送手机验证码 ********************
            sendSmsCode(dto,RegisterConstant.REGISTER_PHONE_KEY);
        }else if ("binder".equals(dto.getType())) { // 类型：手机号绑定
            sendSmsCode(dto, LoginConstant.BINDER_PHONE_KEY); // 不同：手机号绑定只发送验证码
        }
    }

    private void sendSmsCode(SmsCodeDto dto, String redisKey) { // 发送手机验证码都会走这里
        // 5.验证码是否过期。没过期就发送原来的，并且重置过期时间
        String smsCode = "";
        // 从redis中【获取】短信验证码的值
        String redisSmsCode = (String) redisTemplate.opsForValue().get(String.format(redisKey, dto.getPhone()));
        if (StringUtils.isNotBlank(redisSmsCode)) {
            // 如果redis中的值不为空 那么我们发送给客户的就应该是这个
            smsCode = redisSmsCode;
        } else {
            // 如果redis中的值为空 那么我们需要重新生成一个 存到redis中
            smsCode = StrUtils.getComplexRandomString(4);
        }
        log.info("手机号验证码为：{}", smsCode);
        // 6.将手机号验证码【存入】到redis中
        redisTemplate.opsForValue().set(String.format(redisKey, dto.getPhone()), smsCode, RegisterConstant.PHONE_CODE_TTL, TimeUnit.MINUTES);
        // 7.发送短信
//        SmsUtil.sendSms(dto.getPhone(), "尊敬的客户，您的验证码为：" + smsCode + "3分钟内有效！");
    }

    private void imageVerify(SmsCodeDto dto) {
        // 1.参数校验
        if (StringUtils.isBlank(dto.getImageCodeKey()) || StringUtils.isBlank(dto.getImageCodeValue())){
            throw new BussinessException("参数不能为空！（图形验证码不能为空 或 UUID不能为空）");
        }
        // 2.图形验证码是否正确
        String imageCodeRedis = (String) redisTemplate.opsForValue().get(dto.getImageCodeKey());
        if (StringUtils.isBlank(imageCodeRedis) || !dto.getImageCodeValue().equalsIgnoreCase(imageCodeRedis)) {
            throw new BussinessException("图形验证码错误！");
        }
        // 3.两次发送时间是否大于60秒
        Long ttl = redisTemplate.getExpire(String.format(RegisterConstant.REGISTER_PHONE_KEY, dto.getPhone()));
        if (null != ttl && ttl > ((RegisterConstant.PHONE_CODE_TTL - 1) * 60)) {
            throw new BussinessException("请60秒后再获取！");
        }
        // 4.手机号是否注册过 0

        User user = userMapper.findByPhone(dto.getPhone());
        if (null != user) {
            throw new BussinessException("滚去登陆！");
        }
    }
}
